﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UberChess.Structure.Pieces;
using Microsoft.Xna.Framework;
using UberChess.StateTools;
using NUnit.Framework;

namespace UberChess.Evaluation
{
   [Serializable]
   public class EvaluationValues
   {
      private delegate double EvalutionDelegate(State state, Side color);
      private EvalutionDelegate evalMethods;
      private int[] pawRow = { 0, 0, -1, 0, 2, 14, 30, 0 };
      private int[] pawLine = { -2, 0, 3, 4, 5, 1, -2, -2 };
      private int[] pawRowFlipped = new int[8];

      public EvaluationValues()
      {
         //todo clean up
         //evalMethods = new EvalutionDelegate(this.EvaluateKing);
         //evalMethods += new EvalutionDelegate(this.EvaluateBishop);
         //evalMethods += new EvalutionDelegate(this.EvaluateQueen);
         //evalMethods += new EvalutionDelegate(this.EvaluateRook);
         //evalMethods += new EvalutionDelegate(this.EvaluatePawn);
         //evalMethods += new EvalutionDelegate(this.EvaluateKnight);
         //evalMethods += new EvalutionDelegate(this.CanCastle);
         pawRow.CopyTo(pawRowFlipped, 0);
         Array.Reverse(pawRowFlipped);
      }

      
      public double EvaluateBoard(State state, Side playerSide)
      {
         double result = 0.0;

         double smallestMaterielValue = Math.Min(state.MaterialValue(Side.WHITE), state.MaterialValue(Side.BLACK));

         double resultWhite = 0;
         double resultBlack = 0;
         //White
         if (smallestMaterielValue > 1500)
         {
            resultWhite = EvaluateBishop(state, Side.WHITE);
            resultWhite += EvaluateRook(state, Side.WHITE);
            resultWhite += EvaluateKnight(state, Side.WHITE);
            resultWhite += EvaluatePawn(state, Side.WHITE);
            resultWhite += EvaluateQueen(state, Side.WHITE);
            resultWhite += EvaluateKing(state, Side.WHITE);
            //Black
            resultBlack = EvaluateBishop(state, Side.BLACK);
            resultBlack += EvaluateRook(state, Side.BLACK);
            resultBlack += EvaluateKnight(state, Side.BLACK);
            resultBlack += EvaluatePawn(state, Side.BLACK);
            resultBlack += EvaluateQueen(state, Side.BLACK);
            resultBlack += EvaluateKing(state, Side.BLACK);
            //diff
         }
         else
         {
            resultWhite = EvaluateBishop(state, Side.WHITE);
            resultWhite += EvaluateRook(state, Side.WHITE);
            resultWhite += EvaluateKnight(state, Side.WHITE);
            resultWhite += EvaluatePawn(state, Side.WHITE);
            resultWhite += EvaluateQueen(state, Side.WHITE);
            resultWhite += EvaluateKing(state, Side.WHITE, true);
            //Black
            resultBlack = EvaluateBishop(state, Side.BLACK);
            resultBlack += EvaluateRook(state, Side.BLACK);
            resultBlack += EvaluateKnight(state, Side.BLACK);
            resultBlack += EvaluatePawn(state, Side.BLACK);
            resultBlack += EvaluateQueen(state, Side.BLACK);
            resultBlack += EvaluateKing(state, Side.BLACK, true);  
         }



         if (playerSide == Side.WHITE)
             result = resultWhite - resultBlack;
         else
             result = resultBlack - resultWhite;

         return result;
      }


      private double EvaluateKing(State state, Side color, bool EndingOfGame = false )
      {
         double result = 0.0;
         if(!EndingOfGame) return result;
         else
         {
            Vector2[] positions = StateTools.StateTools.GetKingPosition(state, color).ToArray();

            result += positions.Sum(t => -1.0*LenghtToCenter(t));
            return result;
         }
      }

      private double EvaluateQueen(State state, Side color)
      {
         Vector2[] positions = StateTools.StateTools.GetQueenPosition(state, color).ToArray();

         return positions.Sum(t => 900 + 1.0*CoveredFields(state, t));
      }

      private double EvaluateRook(State state, Side color)
      {
         Vector2[] positions = StateTools.StateTools.GetRooksPosition(state, color).ToArray();

         return positions.Sum(t => 500 + 1.5*CoveredFields(state, t));
      }

       //NOTE: Why isn't this being used?
      private double CanCastle(State state, Side color)
      {
         if(state.IsCastlingPossible(color))
         {
            return 16;
         }
         else 
         {
            return 0;
         }
         #region old castling algorithm
         //int colorRow = color == Side.BLACK ? 8 : 0;

            //Rook currentRook  = state.GetPieceAtPosition(new Vector2(8, colorRow)) as Rook;
            //King king         = state.GetPieceAtPosition(new Vector2(5, colorRow)) as King;


            //if (king == null)
            //{
            //   return 0;
            //}
            //else if (currentRook == null)
            //{
            //   return 0;
            //}
            //else
            //{
            //   if (state.GetPieceAtPosition(new Vector2(7, colorRow)).GetType() == typeof(Empty) && 
            //      state.GetPieceAtPosition(new Vector2(6, colorRow)).GetType() == typeof(Empty))
            //   {
            //      if (!currentRook.hasMoved && !king.hasMoved)
            //      {
            //         return 16;
            //      }
            //      else
            //      {
            //         return 0;
            //      }
            //   }
            //   else
            //   {
            //      return 0;
            //   }

         //}
         #endregion old castling algorithm
      }

      private double EvaluateBishop(State state, Side color)
      {
         Vector2[] positions = StateTools.StateTools.GetBishopsPosition(state, color).ToArray();

         return positions.Sum(t => 300 + 2.0*CoveredFields(state, t));
      }

      private double EvaluateKnight(State state, Side color)
      {
         Vector2[] positions = StateTools.StateTools.GetKnightsPosition(state, color).ToArray();

         return positions.Sum(t => 300 + 3.0*(4 - LenghtToCenter(t)));
      }

      private int LenghtToCenter(Vector2 piecePosition)
      {
         Vector2 center = new Vector2(3, 3);

         return Convert.ToInt16(Math.Max(Math.Abs(piecePosition.X - center.X), Math.Abs(piecePosition.Y - center.Y)));
      }

      private double EvaluatePawn(State state, Side color)
      {
         Vector2[] positions = StateTools.StateTools.GetPawnsPosition(state, color).ToArray();
         double result = 0.0;

         int[] parRowLocal = color == Side.WHITE ? pawRowFlipped : pawRow;
         int sideCheck = color == Side.WHITE ? -1 : 1;

         for(int i = 0; i < positions.Length; i++)
         {
             //TODO fix if pawn is at position 7 or 0
             var position = new Vector2(positions[i].X, positions[i].Y + sideCheck);
             if (state.IsWithinBounds(position))
             {

                 bool dobbelPawn = state.GetPieceAtPosition(position).GetType()
                                   == typeof (Pawn) && state.GetPieceAtPosition(position).GetSide() == color
                                       ? true
                                       : false;
                 if (!dobbelPawn)
                 {
                     int lineLocal = color == Side.WHITE ? 7 - (int) positions[i].Y : (int) positions[i].Y;
                     result += 100 + parRowLocal[(int) positions[i].Y] + pawLine[(int) positions[i].X]*lineLocal/2.0;
                 }
                 else
                 {
                     return -8;
                 }
             }
         }

         return result;
      }

      

      private static int CoveredFields(State state, Vector2 position)
      {
         return (state.GetPieceAtPosition(position).GetPossibleMoves(state).Count);
      }

   }
}
